 
  

 






<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
<html>

<!-- Mirrored from www.javapractices.com/topic/TopicAction.do?Id=154 by HTTrack Website Copier/3.x [XR&CO'2010], Sun, 12 Jun 2011 17:28:07 GMT -->
<!-- Added by HTTrack --><meta http-equiv="content-type" content="text/html;charset=UTF-8"><!-- /Added by HTTrack -->
<head>
 <title>
  Java Practices -> Preferences dialogs
 </title>
 <link rel="stylesheet" type="text/css" href="../stylesheet8.css" media="all">
 
 <link rel="shortcut icon" href='../images/favicon.ico' type="image/vnd.microsoft.icon">
 <meta name="description" content="Concise presentations of java programming practices, tasks, and conventions, amply illustrated with syntax highlighted code examples.">
 
 <meta name='keywords' content='EditUserPreferencesAction,PreferencesEditor,QuoteTablePreferencesEditor,preferences,swing,java,java programming,java practices,java idiom,java style,java design patterns,java coding conventions,'>
 
 
</head>
 
<body>


<div class='menu-bar'>
 
  <a href='../home/HomeAction.html' title='Table of Contents'>Home</a> |
  <a href='../vote/VoteSummaryAction-2.html' title='View Poll Results'>Poll</a> |
   
  <A href='../feedback/FeedbackAction451f-2.html?Operation=Show' title='Send Your Feedback'>Wiki</a> |
  <b><a href='../source/SourceAction-2.html' title='Grab Source Code'>Source Code</a></b><IMG class='no-margin' SRC="../images/goldstar.gif" ALT=""> |

  <a href='http://www.web4j.com/Java_Web_Application_Framework_Overview.jsp?From=1' title='Free Download - Java Web Application Framework'><b>WEB4J</b></a> |
  
  <a href='http://www.date4j.net/' title='Replacement for java.util.Date'><b>DATE4J</b></a> |

   <a href='../references/ReferencesAction-2.html' title='References'>Links</a>
   
  <form action='http://www.javapractices.com/search/SearchAction.do' method='get' class='search-form'>
   <input type='text' name='SearchTerms' value="" size=12 maxlength=50 class='search'>
   <input type='submit' value="Search">
  </form>
 
</div>

<P>



  

 






<p class="display-messages">

 

 

</p>


<div class="main-layout">
 
   

 




<div class='page-title'>Preferences dialogs</div>

<div class='main-body'>
 
<br>Settings for user preferences are used in most graphical applications.
These settings control the operation and appearance of a program, and need
to be available to many classes. On the other hand, the dialogs for user
preferences are usually quite extensive, and can take a long time to build
and display to the user.
<p>An advantageous design would allow quick programmatic access to preferences,
but construct GUIs only if necessary.

<p><b>Example</b>

<p>A common style is to use a <tt>JTabbedPane</tt>, with each pane corresponding
to a set of related preferences :
<p><IMG SRC="../images/EditPreferences.gif" height=453 width=292 ALT="Typical Preferences Dialog" border=0>
<p>Here, each pane is defined as an implementation of an interface - <tt>PreferencesEditor</tt>
:
<br>
<PRE>

<span class='keyword'>package</span> hirondelle.stocks.preferences;

<span class='keyword'>import</span> javax.swing.JComponent;

<span class='comment'>/**
* Allows editing of a set of related user preferences.
*
* &lt;P&gt;Implementations of this interface do not define a "stand-alone" GUI, 
* but rather a component (usually a &lt;tt&gt;JPanel&lt;/tt&gt;) which can be used by the 
* caller in any way they want. Typically, a set of &lt;tt&gt;PreferencesEditor&lt;/tt&gt; 
* objects are placed in a &lt;tt&gt;JTabbedPane&lt;/tt&gt;, one per pane.
*/</span>
<span class='keyword'>public</span> <span class='keyword'>interface</span> PreferencesEditor { 

  <span class='comment'>/**
  * Return a GUI component which allows the user to edit this set of related 
  * preferences.
  */</span>  
  JComponent getUI();

  <span class='comment'>/**
  * The name of the tab in which this &lt;tt&gt;PreferencesEditor&lt;/tt&gt;
  * will be placed. 
  */</span>
  String getTitle();

  <span class='comment'>/**
  * The mnemonic to appear in the tab name.
  *
  * &lt;P&gt;Must match a letter appearing in {@link #getTitle}.
  * Use constants defined in &lt;tt&gt;KeyEvent&lt;/tt&gt;, for example &lt;tt&gt;KeyEvent.VK_A&lt;/tt&gt;.
  */</span>
  <span class='keyword'>int</span> getMnemonic();
  
  <span class='comment'>/**
  * Store the related preferences as they are currently displayed, overwriting
  * all corresponding settings.
  */</span>
  <span class='keyword'>void</span> savePreferences();

  <span class='comment'>/**
  * Reset the related preferences to their default values, but only as 
  * presented in the GUI, without affecting stored preference values.
  *
  * &lt;P&gt;This method may not apply in all cases. For example, if the item 
  * represents a config which has no meaningful default value (such as a mail server 
  * name), the desired behavior may be to only allow a manual change. In such a 
  * case, the implementation of this method must be a no-operation. 
  */</span>
  <span class='keyword'>void</span> matchGuiToDefaultPreferences();
}
 
</PRE>
<br>
<br>The <tt>getUI</tt> method of this interface defines the graphical aspect
of a <tt>PreferencesEditor</tt> - implementations do not <em>extend</em> a <tt>JComponent</tt>,
but rather <em>return</em> a <tt>JComponent</tt> from the <tt>getUI</tt> method.
This allows callers to access preference values from implementations of
<tt>PreferencesEditor</tt>
without necessarily constructing a GUI.
<p>Here is an example implementation for the preferences shown above. Note
the addition of these methods which allow programmatic, read-only access
to stored preference values (and
<i>not</i> the preference values as displayed
in the GUI) :
<ul>
<li>
<tt>hasHorizontalLines</tt></li>

<li>
<tt>hasVerticalLines</tt></li>

<li>
<tt>getRowHeight</tt></li>

<li>
<tt>getSortBy</tt></li>

<li>
<tt>getColumnOrder</tt></li>

<li>
<tt>getUpdateFrequency</tt></li>
</ul>
This implementation extends <tt>Observable</tt>, such that interested classes
may register their interest in changes to this set of preferences.
<br>
<PRE>

<span class='keyword'>package</span> hirondelle.stocks.preferences;

<span class='keyword'>import</span> java.awt.*;
<span class='keyword'>import</span> java.awt.event.*;
<span class='keyword'>import</span> javax.swing.*;
<span class='keyword'>import</span> java.util.*;
<span class='keyword'>import</span> java.util.logging.*;
<span class='keyword'>import</span> java.util.prefs.*;

<span class='keyword'>import</span> hirondelle.stocks.table.QuoteField;
<span class='keyword'>import</span> hirondelle.stocks.util.Util;
<span class='keyword'>import</span> hirondelle.stocks.util.ui.UiConsts;
<span class='keyword'>import</span> hirondelle.stocks.util.ui.UiUtil;

<span class='comment'>/**
* Graphical component allows editing of user preferences related to the 
* {@link hirondelle.stocks.table.QuoteTable},
* and programmatic read-only access to these preferences.
*/</span>
<span class='keyword'>public</span> <span class='keyword'>final</span> <span class='keyword'>class</span> QuoteTablePreferencesEditor <span class='keyword'>extends</span> Observable 
  <span class='keyword'>implements</span> PreferencesEditor {

  <span class='keyword'>public</span> JComponent getUI() {
    JPanel content = <span class='keyword'>new</span> JPanel();
    GridBagLayout gridbag = <span class='keyword'>new</span> GridBagLayout();
    content.setLayout(gridbag);
    addSortField(content);
    addHorizontalVerticalLines(content);
    addRowHeight(content);
    addUpdateFrequency(content);
    addColumnOrder(content);
    addRestore(content);
    matchGuiToStoredPrefs();
    <span class='keyword'>return</span> content;
  }

  <span class='keyword'>public</span> String getTitle() {
    <span class='keyword'>return</span> TITLE;
  }

  <span class='keyword'>public</span> <span class='keyword'>int</span> getMnemonic() {
    <span class='keyword'>return</span> MNEMONIC;
  }

  <span class='keyword'>public</span> <span class='keyword'>void</span> savePreferences() {
    fLogger.fine(<span class='literal'>"Updating table preferences."</span>);
    fPrefs.putBoolean(HORIZONTAL_LINES_KEY, fHorizontalLines.isSelected());
    fPrefs.putBoolean(VERTICAL_LINES_KEY, fVerticalLines.isSelected());
    fPrefs.putInt(ROW_HEIGHT_KEY, fRowSizeModel.getNumber().intValue());
    fPrefs.put(SORT_FIELD_KEY, fSortField.getSelectedItem().toString());
    fPrefs.put(COLUMN_ORDER_KEY, fColumnOrderEditor.getItems().toString());
    fPrefs.putInt(UPDATE_FREQ_KEY, fUpdateFreqModel.getNumber().intValue());
    setChanged();
    notifyObservers();
  }

  <span class='keyword'>public</span> <span class='keyword'>void</span> matchGuiToDefaultPreferences() {
    fHorizontalLines.setSelected(HORIZONTAL_LINES_DEFAULT);
    fVerticalLines.setSelected(VERTICAL_LINES_DEFAULT);
    fRowSizeModel.setValue(<span class='keyword'>new</span> Integer(ROW_HEIGHT_DEFAULT));
    fSortField.setSelectedItem(QuoteField.valueFrom(SORT_FIELD_DEFAULT));
    fColumnOrderEditor.setItems(parseRawColumnOrder(COLUMN_ORDER_DEFAULT));
    fUpdateFreqModel.setValue(<span class='keyword'>new</span> Integer(UPDATE_FREQ_DEFAULT));
  }

  <span class='comment'>/**
  * Return preference for the display of horizontal lines for each row.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>boolean</span> hasHorizontalLines() {
    <span class='keyword'>return</span> fPrefs.getBoolean(HORIZONTAL_LINES_KEY, HORIZONTAL_LINES_DEFAULT);
  }

  <span class='comment'>/**
  * Return preference for the display of vertical lines for each column.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>boolean</span> hasVerticalLines() {
    <span class='keyword'>return</span> fPrefs.getBoolean(VERTICAL_LINES_KEY, VERTICAL_LINES_DEFAULT);
  }

  <span class='comment'>/**
   * Return the height of each row in pixels, in the range &lt;tt&gt;16..32&lt;/tt&gt;
   * (inclusive).
   */</span>
  <span class='keyword'>public</span> <span class='keyword'>int</span> getRowHeight() {
    <span class='keyword'>return</span> fPrefs.getInt(ROW_HEIGHT_KEY, ROW_HEIGHT_DEFAULT);
  }

  <span class='comment'>/**
   * Return a field identifier, but no ascending-descending indicator.
   */</span>
  <span class='keyword'>public</span> QuoteField getSortField() {
    String fieldName = fPrefs.get(SORT_FIELD_KEY, SORT_FIELD_DEFAULT);
    <span class='keyword'>return</span> QuoteField.valueFrom(fieldName);
  }

  <span class='comment'>/**
   * Return &lt;tt&gt;Set&lt;/tt&gt; of {@link QuoteField} objects, whose
   * iteration order reflects the user's preferred column order.
   */</span>
  <span class='keyword'>public</span> Set&lt;Object&gt; getColumnOrder() {
    <span class='keyword'>return</span> parseRawColumnOrder(fPrefs.get(COLUMN_ORDER_KEY, COLUMN_ORDER_DEFAULT));
  }

  <span class='comment'>/**
   * Return the number of minutes to wait between periodic updates, in the range
   * &lt;tt&gt;1..60&lt;/tt&gt;.
   */</span>
  <span class='keyword'>public</span> <span class='keyword'>int</span> getUpdateFrequency() {
    <span class='keyword'>return</span> fPrefs.getInt(UPDATE_FREQ_KEY, UPDATE_FREQ_DEFAULT);
  }

  <span class='comment'>// PRIVATE //
</span>  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> String TITLE = <span class='literal'>"Quote Table"</span>;
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> <span class='keyword'>int</span> MNEMONIC = KeyEvent.VK_Q;
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> String STOCKS_TABLE_NODE_NAME = 
    <span class='literal'>"stocksmonitor/ui/prefs/StocksTable"</span>
  ;
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> <span class='keyword'>boolean</span> HORIZONTAL_LINES_DEFAULT = <span class='keyword'>true</span>;
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> String HORIZONTAL_LINES_KEY = <span class='literal'>"HorizontalLines"</span>;
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> <span class='keyword'>boolean</span> VERTICAL_LINES_DEFAULT = <span class='keyword'>true</span>;
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> String VERTICAL_LINES_KEY = <span class='literal'>"VerticalLines"</span>;
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> <span class='keyword'>int</span> MAX_ROW_HEIGHT = <span class='literal'>32</span>;
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> <span class='keyword'>int</span> MIN_ROW_HEIGHT = <span class='literal'>16</span>;
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> <span class='keyword'>int</span> INITIAL_ROW_HEIGHT = MIN_ROW_HEIGHT;
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> <span class='keyword'>int</span> STEP_SIZE = <span class='literal'>1</span>;
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> <span class='keyword'>int</span> ROW_HEIGHT_DEFAULT = MIN_ROW_HEIGHT;
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> String ROW_HEIGHT_KEY = <span class='literal'>"RowHeight"</span>;
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> String SORT_FIELD_DEFAULT = <span class='literal'>"Stock"</span>;
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> String SORT_FIELD_KEY = <span class='literal'>"SortBy"</span>;
  <span class='comment'>// This preference is unusual in that in needs a bit of parsing
</span>  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> String COLUMN_ORDER_DEFAULT = 
    <span class='literal'>"[Stock, Price, Change, %Change, Profit, %Profit]"</span>
  ;
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> String COLUMN_ORDER_KEY = <span class='literal'>"ColumnOrder"</span>;
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> <span class='keyword'>int</span> MAX_UPDATE_FREQ = <span class='literal'>60</span>;
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> <span class='keyword'>int</span> MIN_UPDATE_FREQ = <span class='literal'>1</span>;
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> <span class='keyword'>int</span> UPDATE_FREQ_DEFAULT = <span class='literal'>1</span>; <span class='comment'>// seconds
</span>  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> String UPDATE_FREQ_KEY = <span class='literal'>"UpdateFrequency"</span>;

  <span class='keyword'>private</span> Preferences fPrefs = Preferences.userRoot().node(STOCKS_TABLE_NODE_NAME);
  <span class='keyword'>private</span> JCheckBox fHorizontalLines;
  <span class='keyword'>private</span> JCheckBox fVerticalLines;
  <span class='keyword'>private</span> SpinnerNumberModel fRowSizeModel;
  <span class='keyword'>private</span> JComboBox fSortField;
  <span class='keyword'>private</span> OrderEditor fColumnOrderEditor;
  <span class='keyword'>private</span> SpinnerNumberModel fUpdateFreqModel;

  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> Logger fLogger = Util.getLogger(QuoteTablePreferencesEditor.<span class='keyword'>class</span>);

  <span class='keyword'>private</span> <span class='keyword'>void</span> addSortField(JPanel aContent) {
    JLabel sortBy = <span class='keyword'>new</span> JLabel(<span class='literal'>"Sort By:"</span>);
    sortBy.setDisplayedMnemonic(KeyEvent.VK_S);
    sortBy.setToolTipText(<span class='literal'>"Always descending order"</span>);
    aContent.add(sortBy, getConstraints(<span class='literal'>0</span>, <span class='literal'>0</span>));

    DefaultComboBoxModel sortByModel = <span class='keyword'>new</span> DefaultComboBoxModel(QuoteField.values());
    fSortField = <span class='keyword'>new</span> JComboBox(sortByModel);
    sortBy.setLabelFor(fSortField);
    aContent.add(fSortField, getConstraints(<span class='literal'>0</span>, <span class='literal'>1</span>));
  }

  <span class='keyword'>private</span> <span class='keyword'>void</span> addHorizontalVerticalLines(JPanel aContent) {
    JLabel show = <span class='keyword'>new</span> JLabel(<span class='literal'>"Show:"</span>);
    aContent.add(show, getConstraints(<span class='literal'>1</span>, <span class='literal'>0</span>));

    fHorizontalLines = <span class='keyword'>new</span> JCheckBox(<span class='literal'>"Horizontal Lines"</span>);
    fHorizontalLines.setMnemonic(KeyEvent.VK_H);
    aContent.add(fHorizontalLines, getConstraints(<span class='literal'>1</span>, <span class='literal'>1</span>));

    fVerticalLines = <span class='keyword'>new</span> JCheckBox(<span class='literal'>"Vertical Lines"</span>);
    fVerticalLines.setMnemonic(KeyEvent.VK_V);
    aContent.add(fVerticalLines, getConstraints(<span class='literal'>1</span>, <span class='literal'>2</span>, <span class='literal'>2</span>, <span class='literal'>1</span>));
  }

  <span class='keyword'>private</span> <span class='keyword'>void</span> addRowHeight(JPanel aContent) {
    JLabel rowHeight = <span class='keyword'>new</span> JLabel(<span class='literal'>"Row Height:"</span>);
    rowHeight.setDisplayedMnemonic(KeyEvent.VK_R);
    rowHeight.setToolTipText(<span class='literal'>"Height in pixels of table rows"</span>);
    aContent.add(rowHeight, getConstraints(<span class='literal'>2</span>, <span class='literal'>0</span>));
    fRowSizeModel = <span class='keyword'>new</span> SpinnerNumberModel(
      INITIAL_ROW_HEIGHT, MIN_ROW_HEIGHT, MAX_ROW_HEIGHT, STEP_SIZE
    );
    JSpinner rowHeightSelector = <span class='keyword'>new</span> JSpinner(fRowSizeModel);
    rowHeight.setLabelFor(rowHeightSelector);
    aContent.add(rowHeightSelector, getConstraints(<span class='literal'>2</span>, <span class='literal'>1</span>));
  }

  <span class='keyword'>private</span> <span class='keyword'>void</span> addUpdateFrequency(JPanel aContent) {
    JLabel updateFreq = <span class='keyword'>new</span> JLabel(<span class='literal'>"Update Freq:"</span>);
    updateFreq.setDisplayedMnemonic(KeyEvent.VK_U);
    updateFreq.setToolTipText(<span class='literal'>"Refresh interval in minutes"</span>);
    aContent.add(updateFreq, getConstraints(<span class='literal'>2</span>, <span class='literal'>2</span>));

    <span class='keyword'>int</span> initialFreqValue = MIN_UPDATE_FREQ;
    fUpdateFreqModel = <span class='keyword'>new</span> SpinnerNumberModel(
      initialFreqValue, MIN_UPDATE_FREQ, MAX_UPDATE_FREQ, <span class='literal'>1</span>
    );
    JSpinner updateFreqSelector = <span class='keyword'>new</span> JSpinner(fUpdateFreqModel);
    updateFreq.setLabelFor(updateFreqSelector);
    aContent.add(updateFreqSelector, getConstraints(<span class='literal'>2</span>, <span class='literal'>3</span>));
  }

  <span class='keyword'>private</span> <span class='keyword'>void</span> addColumnOrder(JPanel aContent) {
    JLabel columnOrder = <span class='keyword'>new</span> JLabel(<span class='literal'>"Column Order:"</span>);
    columnOrder.setDisplayedMnemonic(KeyEvent.VK_C);
    GridBagConstraints columnOrderConstraints = getConstraints(<span class='literal'>3</span>, <span class='literal'>0</span>);
    columnOrderConstraints.anchor = GridBagConstraints.NORTH;
    aContent.add(columnOrder, columnOrderConstraints);

    fColumnOrderEditor = <span class='keyword'>new</span> OrderEditor(<span class='literal'>"Up"</span>, <span class='literal'>"Down"</span>);
    <span class='comment'>// Demonstrates alternate ctor using icons:
</span>    <span class='comment'>// fColumnOrderEditor = new OrderEditor(
</span>    <span class='comment'>// UiUtil.getImageIcon("/toolbarButtonGraphics/navigation/Up"),
</span>    <span class='comment'>// UiUtil.getImageIcon("/toolbarButtonGraphics/navigation/Down"),
</span>    <span class='comment'>// UiConsts.ONE_SPACE * 15 );
</span>    columnOrder.setLabelFor(fColumnOrderEditor);
    GridBagConstraints orderEditorConstraints = UiUtil.getConstraints(<span class='literal'>3</span>, <span class='literal'>1</span>);
    orderEditorConstraints.insets = <span class='keyword'>new</span> Insets(UiConsts.ONE_SPACE, <span class='literal'>0</span>, <span class='literal'>0</span>, <span class='literal'>0</span>);
    aContent.add(fColumnOrderEditor, orderEditorConstraints);
  }

  <span class='keyword'>private</span> <span class='keyword'>void</span> addRestore(JPanel aContent) {
    JButton restore = <span class='keyword'>new</span> JButton(<span class='literal'>"Restore Defaults"</span>);
    restore.setMnemonic(KeyEvent.VK_D);
    restore.addActionListener(<span class='keyword'>new</span> ActionListener() {
      <span class='keyword'>public</span> <span class='keyword'>void</span> actionPerformed(ActionEvent event) {
        matchGuiToDefaultPreferences();
      }
    });
    GridBagConstraints constraints = UiUtil.getConstraints(<span class='literal'>3</span>, <span class='literal'>2</span>, <span class='literal'>2</span>, <span class='literal'>1</span>);
    constraints.anchor = GridBagConstraints.SOUTH;
    constraints.insets = <span class='keyword'>new</span> Insets(<span class='literal'>0</span>, <span class='literal'>0</span>, <span class='literal'>0</span>, <span class='literal'>0</span>);
    aContent.add(restore, constraints);
  }

  <span class='comment'>/**
   * Return a &lt;tt&gt;Set&lt;/tt&gt; of {@link QuoteField} objects, whose
   * iteration order corresponds to the preferred column order.
   */</span>
  <span class='keyword'>private</span> Set&lt;Object&gt; parseRawColumnOrder(String aRawColumnOrderPref) {
    java.util.List&lt;String&gt; columnNames = Util.getListFromString(aRawColumnOrderPref);
    Set&lt;Object&gt; result = <span class='keyword'>new</span> LinkedHashSet&lt;Object&gt;();
    <span class='keyword'>for</span>(String fieldName: columnNames){
      result.add(QuoteField.valueFrom(fieldName));
    }
    assert (result.size() == QuoteField.values().length);
    <span class='keyword'>return</span> result;
  }

  <span class='keyword'>private</span> <span class='keyword'>void</span> matchGuiToStoredPrefs() {
    fHorizontalLines.setSelected(hasHorizontalLines());
    fVerticalLines.setSelected(hasVerticalLines());
    fRowSizeModel.setValue(<span class='keyword'>new</span> Integer(getRowHeight()));
    fSortField.setSelectedItem(getSortField());
    fColumnOrderEditor.setItems(getColumnOrder());
    fUpdateFreqModel.setValue(<span class='keyword'>new</span> Integer(getUpdateFrequency()));
  }

  <span class='keyword'>private</span> GridBagConstraints getConstraints(<span class='keyword'>int</span> aY, <span class='keyword'>int</span> aX) {
    GridBagConstraints result = UiUtil.getConstraints(aY, aX);
    addBottom(result);
    <span class='keyword'>return</span> result;
  }

  <span class='keyword'>private</span> GridBagConstraints getConstraints(<span class='keyword'>int</span> aY, <span class='keyword'>int</span> aX, <span class='keyword'>int</span> aWidth, <span class='keyword'>int</span> aHeight) {
    GridBagConstraints result = UiUtil.getConstraints(aY, aX, aWidth, aHeight);
    addBottom(result);
    <span class='keyword'>return</span> result;
  }

  <span class='keyword'>private</span> <span class='keyword'>void</span> addBottom(GridBagConstraints aConstraints) {
    aConstraints.insets = <span class='keyword'>new</span> Insets(<span class='literal'>0</span>, <span class='literal'>0</span>, UiConsts.ONE_SPACE, UiConsts.ONE_SPACE);
  }

  <span class='comment'>/**
   * Developer tool for removing old preferences and restarting from the beginning.
   */</span>
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>void</span> main(String... aArgs) {
    QuoteTablePreferencesEditor thing = <span class='keyword'>new</span> QuoteTablePreferencesEditor();
    <span class='keyword'>try</span> {
      thing.fPrefs.removeNode();
    }
    <span class='keyword'>catch</span> (BackingStoreException ex) {
      fLogger.severe(<span class='literal'>"Cannot access preferences."</span>);
    }
    fLogger.severe(<span class='literal'>"Done."</span>);
  }
}
 
</PRE>
<br>
<br>Here is a high level <tt>Action</tt> class which displays a preferences
dialog. It uses a <tt>List</tt> of <tt>PreferencesEditor</tt> objects passed
to the constructor.
<br>
<PRE>

<span class='keyword'>package</span> hirondelle.stocks.preferences;

<span class='keyword'>import</span> java.awt.event.*;
<span class='keyword'>import</span> javax.swing.*;
<span class='keyword'>import</span> java.util.*;
<span class='keyword'>import</span> java.util.logging.*;

<span class='keyword'>import</span> hirondelle.stocks.util.Args;
<span class='keyword'>import</span> hirondelle.stocks.util.ui.StandardEditor;
<span class='keyword'>import</span> hirondelle.stocks.util.ui.UiUtil;
<span class='keyword'>import</span> hirondelle.stocks.preferences.PreferencesEditor;
<span class='keyword'>import</span> hirondelle.stocks.util.Util;

<span class='comment'>/**
* Present dialog to allow update of user preferences.
*
* &lt;P&gt;Related preferences are grouped together and placed in 
* a single pane of a &lt;tt&gt;JTabbedPane&lt;/tt&gt;, which corresponds to an 
* implementation of {@link PreferencesEditor}. Values are pre-populated with 
* current values for preferences.
*
*&lt;P&gt;Most preferences have default values. If so, a  
* &lt;tt&gt;Restore Defaults&lt;/tt&gt; button is provided for that set of related 
* preferences.
*
*&lt;P&gt;Preferences are not changed until the &lt;tt&gt;OK&lt;/tt&gt; button is pressed. 
* Exception: the logging preferences take effect immediately, without the need 
* for hitting &lt;tt&gt;OK&lt;/tt&gt;.
*/</span>
<span class='keyword'>public</span> <span class='keyword'>final</span> <span class='keyword'>class</span> EditUserPreferencesAction <span class='keyword'>extends</span> AbstractAction {

  <span class='comment'>/**
  * Constructor.
  *  
  * @param aFrame parent window to which this dialog is attached.
  * @param aPrefEditors contains implementations of {@link PreferencesEditor}, 
  * each of which is placed in a pane of a &lt;tt&gt;JTabbedPane&lt;/tt&gt;.
  */</span>
  <span class='keyword'>public</span> EditUserPreferencesAction (JFrame aFrame, List&lt;PreferencesEditor&gt; aPrefEditors) {
    <span class='keyword'>super</span>(<span class='literal'>"Preferences..."</span>, UiUtil.getEmptyIcon()); 
    Args.checkForNull(aFrame);
    Args.checkForNull(aPrefEditors);
    fFrame = aFrame;
    putValue(SHORT_DESCRIPTION, <span class='literal'>"Update user preferences"</span>);
    putValue(LONG_DESCRIPTION, <span class='literal'>"Allows user input of preferences."</span>);
    putValue(MNEMONIC_KEY, <span class='keyword'>new</span> Integer(KeyEvent.VK_P) );    
    fPrefEditors = aPrefEditors;
  }

  <span class='comment'>/** Display the user preferences dialog.  */</span>
  <span class='keyword'>public</span> <span class='keyword'>void</span> actionPerformed(ActionEvent event) {
    fLogger.info(<span class='literal'>"Showing user preferences dialog."</span>);
    <span class='comment'>//lazy construction: fEditor is created only once, when this action 
</span>    <span class='comment'>//is explicitly invoked
</span>    <span class='keyword'>if</span> ( fEditor == <span class='keyword'>null</span> ) {
      fEditor = <span class='keyword'>new</span> Editor(<span class='literal'>"Edit Preferences"</span>, fFrame);
    }
    fEditor.showDialog();
  }
  
  <span class='comment'>// PRIVATE //
</span>  <span class='keyword'>private</span> JFrame fFrame;
  <span class='keyword'>private</span> java.util.List&lt;PreferencesEditor&gt; fPrefEditors;
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> Logger fLogger = Util.getLogger(EditUserPreferencesAction.<span class='keyword'>class</span>);  
  
  <span class='comment'>/**
  * Specifying this as a field allows for "lazy" creation and use of the GUI, which is 
  * of particular importance for a preferences dialog, since they are usually heavyweight, 
  * and have a large number of components.
  */</span>
  <span class='keyword'>private</span> Editor fEditor;
  
  <span class='comment'>/**
  * Return GUI for editing all preferences, pre-populated with current 
  * values.
  */</span>
  <span class='keyword'>private</span> JComponent getPrefEditors(){
    JTabbedPane content = <span class='keyword'>new</span> JTabbedPane();
    content.setTabPlacement(JTabbedPane.LEFT);
    <span class='keyword'>int</span> idx = <span class='literal'>0</span>;
    <span class='keyword'>for</span>(PreferencesEditor prefEditor: fPrefEditors) {
      JComponent editorGui = prefEditor.getUI();
      editorGui.setBorder(UiUtil.getStandardBorder());
      content.addTab(prefEditor.getTitle() , editorGui);
      content.setMnemonicAt(idx, prefEditor.getMnemonic());
      ++idx;
    }
    <span class='keyword'>return</span> content;
  }
  
  <span class='comment'>/** Called only when the user hits the OK button.  */</span>
  <span class='keyword'>private</span> <span class='keyword'>void</span> saveSettings(){
    fLogger.fine(<span class='literal'>"User selected OK. Updating table preferences."</span>);
    <span class='keyword'>for</span>(PreferencesEditor prefEditor: fPrefEditors) {
      prefEditor.savePreferences();
    }
  }
  
  <span class='comment'>/**
  * An example of a nested class which is nested because it is attached only 
  * to the enclosing class, and it cannot act as superclass since multiple 
  * inheritance of implementation is not possible. 
  * 
  * The implementation of this nested class is kept short by calling methods 
  * of the enclosing class.
  */</span>
  <span class='keyword'>private</span> <span class='keyword'>final</span> <span class='keyword'>class</span> Editor <span class='keyword'>extends</span> StandardEditor { 
    
    Editor(String aTitle, JFrame aParent){
      <span class='keyword'>super</span>(aTitle, aParent, StandardEditor.CloseAction.HIDE);
    }

    <span class='keyword'>public</span> JComponent getEditorUI () {
      JPanel content = <span class='keyword'>new</span> JPanel();
      content.setLayout( <span class='keyword'>new</span> BoxLayout(content, BoxLayout.Y_AXIS) );
      content.add( getPrefEditors() );
      <span class='comment'>//content.setMinimumSize(new Dimension(300,300) );
</span>      <span class='keyword'>return</span> content;
    }
    
    <span class='keyword'>public</span> <span class='keyword'>void</span> okAction() {
      saveSettings();
      dispose();
    }
  }  
}
 
</PRE>
<br>
<br>
<br>

</div>




<div class='topic-section'>See Also :</div>
<div class='main-body'>
 
  
  <a href='TopicAction7910-2.html?Id=150'>Standardized dialogs</a> <br>
 
  
  <a href='TopicAction54be-2.html?Id=155'>Using preferences</a> <br>
 
</div>


<div class='topic-section'>Would you use this technique?</div>
<div class='main-body'>
  
  <form action="http://www.javapractices.com/vote/AddVoteAction.do" method='post'>
    Yes<input type='radio' name='Choice' value='Y' >
    &nbsp;&nbsp;No<input type='radio' name='Choice' value='N'>
    &nbsp;&nbsp;Undecided<input type='radio' name='Choice' value="?" >
    &nbsp;&nbsp;<input type=submit value="Vote" >
    <input type='hidden' name='Operation' value='Apply'>
    <input type='hidden' name='TopicId' value='154'>
  </form>
</div>

<div style='height:10.0em;'></div>

 
 
</div>

  

 





<div align='center' class='legalese'>  
&copy; 2011 Hirondelle Systems |
<a href='../source/SourceAction-2.html'><b>Source Code</b></a><IMG class='no-margin' SRC="../images/goldstar.gif" ALT=""> |
<a href="mailto:webmaster@javapractices.com">Contact</a> |
<a href="http://creativecommons.org/licenses/by-nc-sa/1.0/">License</a> |
<a href='../apps/cjp.rss'>RSS</a>
<!-- ukey="2AC36CD2" -->
<!-- ckey="16DF3D87" -->
<br>

 Individual code snippets can be used under this <a href='../LICENSE.txt'>BSD license</a> - Last updated on June 6, 2010.<br>
 Over 150,000 unique IPs last month - <span title='Java Practices 2.6.5, Mon May 16 00:00:00 EDT 2011'>Built with</span> <a href='http://www.web4j.com/'>WEB4J</a>.<br>
 - In Memoriam : Bill Dirani -
</div>

<script src="../../www.google-analytics.com/urchin.js" type="text/javascript">
</script>
<script type="text/javascript">
_uacct = "UA-2633428-1";
urchinTracker();
</script>



</body>

<!-- Mirrored from www.javapractices.com/topic/TopicAction.do?Id=154 by HTTrack Website Copier/3.x [XR&CO'2010], Sun, 12 Jun 2011 17:28:07 GMT -->
<!-- Added by HTTrack --><meta http-equiv="content-type" content="text/html;charset=UTF-8"><!-- /Added by HTTrack -->
</html>
